/*
 * BSM6.0
 *
 * Copyright 2012-2013 (C) SINODATA CO., LTD. All Rights Reserved.
 */
package com.sinodata.bsm.inmp.task;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;

import com.sinodata.bsm.common.constants.PropertyConstants;
import com.sinodata.bsm.common.vo.CollectSchedule;
import com.sinodata.bsm.common.vo.CollectTask;
import com.sinodata.bsm.common.vo.Res;
import com.sinodata.bsm.inmp.cache.CacheFactory;
import com.sinodata.bsm.inmp.cache.ResCache;
import com.sinodata.bsm.inmp.service.CollectorService;
import com.sinodata.bsm.inmp.service.ServiceFactory;
import com.sinodata.bsm.inmp.task.gab.AnjianEventCollectJob;
import com.sinodata.bsm.inmp.task.gab.ShujiwangguanEventCollectJob;
import com.sinodata.bsm.inmp.task.gab.WenshiduEventCollectJob;
import com.sinodata.bsm.inmp.task.gab.WsdPerformaceDataCollectorJob;
import com.sinodata.bsm.inmp.task.gab.WshPropertyCollectJob;
import com.sinodata.bsm.inmp.util.SystemContext;

/**
 * <p>
 * Description: 
 * </p>
 *
 * @author tangli
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-5-19 上午10:49:34          tangli         1.0         To create
 * </p>
 *
 * @since 
 * @see     
 */
public class TaskManager {
    static final String JOB_KEY_INTERVAL = "interval";

    private static TaskManager instance = new TaskManager();
    private static Logger logger = Logger.getLogger(TaskManager.class);
    private Scheduler scheduler;

    private final ResCache resCache = (ResCache) CacheFactory.getCache(ResCache.class);
    private final CollectorService collectorService = (CollectorService) ServiceFactory.get("CollectorService");

    /**
     * 
     */
    private TaskManager() {
        try {
            scheduler = new StdSchedulerFactory("inmp-conf/quartz.properties").getScheduler();
            scheduler.start();
        } catch (SchedulerException e) {
            logger.error("初始化任务管理器失败", e);
        }
    }

    public static TaskManager getInstance() {
        return instance;
    }

    /**
     * 获取朗易历史性能指标
     */
    public void startHisPerfJob() {
        JobDetail job = null;
        Trigger trigger = null;
        try {
            String interval = (String) SystemContext.getProperty("poll_interval_indic");
            try {
                Integer.parseInt(interval);
            } catch (Exception e) {
                interval = "-1";
            }

            if ("-1".equals(interval)) {
                return;
            }

            job = newJob(HisPropJob.class).withIdentity("le", "LE").build();
            scheduler.addJob(job, true);
            trigger = makeTrggier(job.getKey(), "LangEasy", 1L, interval);
            trigger.getJobDataMap().put(JOB_KEY_INTERVAL, interval);
            if (trigger != null) {
                scheduler.scheduleJob(trigger);
            }
        } catch (Exception e) {
            logger.error("[TIP]\t 启动获取朗易网络设备历史指标的任务调度失败", e);
        }
    }

    /**
     * 获取OP端口性能数据的JOB
     */
    public void startOPPerfJob() {
        JobDetail job = null;
        Trigger trigger = null;
        try {
            String interval = (String) SystemContext.getProperty("poll_interval_indic");
            try {
                Integer.parseInt(interval);
            } catch (Exception e) {
                interval = "-1";
            }

            if ("-1".equals(interval)) {
                return;
            }

            job = newJob(OpIfPropJob.class).withIdentity("op", "op").build();
            scheduler.addJob(job, true);
            trigger = makeTrggier(job.getKey(), "opmanager", 1L, interval);
            trigger.getJobDataMap().put(JOB_KEY_INTERVAL, interval);
            if (trigger != null) {
                scheduler.scheduleJob(trigger);
            }
        } catch (Exception e) {
            logger.error("[TIP]\t 启动获取OP历史性能指标的任务调度失败", e);
        }
    }

    /**
     * 获取OPmanager事件的JOB
     */
    public void startOpEventJob() {
        JobDetail job = null;
        Trigger trigger = null;
        try {
            String interval = (String) SystemContext.getProperty("poll_interval_event");
            try {
                Integer.parseInt(interval);
            } catch (Exception e) {
                interval = "-1";
            }

            if ("-1".equals(interval)) {
                return;
            }

            job = newJob(OpEventJob.class).withIdentity("ope", "ope").build();
            scheduler.addJob(job, true);
            trigger = makeTrggier(job.getKey(), "opmanagere", 1L, interval);
            trigger.getJobDataMap().put(JOB_KEY_INTERVAL, interval);
            if (trigger != null) {
                scheduler.scheduleJob(trigger);
            }
        } catch (Exception e) {
            logger.error("[TIP]\t 启动获取OPManager的事件的任务调度失败", e);
        }
    }

    /**
     * 获取opstor的事件
     */
    public void startStorEventJob() {
        JobDetail job = null;
        Trigger trigger = null;
        try {
            String interval = (String) SystemContext.getProperty("poll_interval_event");
            try {
                Integer.parseInt(interval);
            } catch (Exception e) {
                interval = "-1";
            }

            if ("-1".equals(interval)) {
                return;
            }

            job = newJob(StorEventJob.class).withIdentity("stor_e", "stor_e").build();
            scheduler.addJob(job, true);
            trigger = makeTrggier(job.getKey(), "opstor_e", 1L, interval);
            trigger.getJobDataMap().put(JOB_KEY_INTERVAL, interval);
            if (trigger != null) {
                scheduler.scheduleJob(trigger);
            }
        } catch (Exception e) {
            logger.error("[TIP]\t 启动获取OPStor中的事件的任务调度失败", e);
        }
    }

    /**
     * 公安部事件类集成
     */
    public void startGabEventJob() {
        JobDetail job = null;
        Trigger trigger = null;
        try {
            String interval = (String) SystemContext.getProperty("poll_interval_indic");
            try {
                Integer.parseInt(interval);
            } catch (Exception e) {
                logger.info("poll_interval_event 解析错误");
                return;
            }
            job = newJob(ShujiwangguanEventCollectJob.class).withIdentity("gab_e", "gab_e").build();
            scheduler.addJob(job, true);
            trigger = makeTrggier(job.getKey(), "gab_e", 1L, interval);
            trigger.getJobDataMap().put(JOB_KEY_INTERVAL, interval);
            if (trigger != null) {
                scheduler.scheduleJob(trigger);
            }
        } catch (Exception e) {
            logger.error("[TIP]\t 启动获取公安部事件集成任务调度失败", e);
        }
    }

    /**
     * 公安部事件类集成
     */
    public void startGabWsdJob() {
        JobDetail job = null;
        Trigger trigger = null;
        try {
            String interval = (String) SystemContext.getProperty("poll_interval_indic");
            try {
                Integer.parseInt(interval);
            } catch (Exception e) {
                logger.info("poll_interval_event 解析错误");
                return;
            }
            job = newJob(WenshiduEventCollectJob.class).withIdentity("gab_wsd", "gab_wsd").build();
            scheduler.addJob(job, true);
            trigger = makeTrggier(job.getKey(), "gab_wsd", 1L, interval);
            trigger.getJobDataMap().put(JOB_KEY_INTERVAL, interval);
            if (trigger != null) {
                scheduler.scheduleJob(trigger);
            }
        } catch (Exception e) {
            logger.error("[TIP]\t 启动获取公安部事件集成任务调度失败", e);
        }
    }

    /**
     * 温湿度性能数据收集job
     */
    public void startWSDPerfJob() {
        JobDetail job = null;
        Trigger trigger = null;
        try {
            String interval = 60 * 10 + "";
            job = newJob(WsdPerformaceDataCollectorJob.class).withIdentity("gab_wsd_perf", "gab_wsd_perf").build();
            scheduler.addJob(job, true);
            trigger = makeTrggier(job.getKey(), "gab_wsd_perf", 1L, interval);
            trigger.getJobDataMap().put(JOB_KEY_INTERVAL, interval);
            if (trigger != null) {
                scheduler.scheduleJob(trigger);
            }
        } catch (Exception e) {
            logger.error("[TIP]\t 启动获取温湿度性能数据job失败", e);
        }
    }

    /**
     * 温湿度性能数据采集job
     */
    public void startWSDPerfCollectJob() {
        JobDetail job = null;
        Trigger trigger = null;
        try {
            String interval = (String) SystemContext.getProperty("poll_interval_indic");
            try {
                Integer.parseInt(interval);
            } catch (Exception e) {
                logger.info("poll_interval_event 解析错误");
                return;
            }
            job = newJob(WshPropertyCollectJob.class).withIdentity("gab_wsd_perf_collect", "gab_wsd_perf_collect").build();
            scheduler.addJob(job, true);
            trigger = makeTrggier(job.getKey(), "gab_wsd_perf_collect", 1L, interval);
            trigger.getJobDataMap().put(JOB_KEY_INTERVAL, interval);
            if (trigger != null) {
                scheduler.scheduleJob(trigger);
            }
        } catch (Exception e) {
            logger.error("[TIP]\t 启动获取公安部温湿度性能数据采集job失败", e);
        }
    }

    /**
     * 安监系统事件集成
     */
    public void startGabAnjianJob() {
        JobDetail job = null;
        Trigger trigger = null;
        try {
            String interval = (String) SystemContext.getProperty("poll_interval_indic");
            try {
                Integer.parseInt(interval);
            } catch (Exception e) {
                logger.info("poll_interval_event 解析错误");
                return;
            }
            job = newJob(AnjianEventCollectJob.class).withIdentity("gab_anjian", "gab_anjian").build();
            scheduler.addJob(job, true);
            trigger = makeTrggier(job.getKey(), "gab_anjian", 1L, interval);
            trigger.getJobDataMap().put(JOB_KEY_INTERVAL, interval);
            if (trigger != null) {
                scheduler.scheduleJob(trigger);
            }
        } catch (Exception e) {
            logger.error("[TIP]\t 启动获取公安部安监系统事件调度失败", e);
        }
    }

    public void stopAllTasks() {
        GroupMatcher<JobKey> gm = GroupMatcher.groupStartsWith("FIXED_");
        try {
            scheduler.getJobKeys(gm);
            List<JobKey> jobKeys = new ArrayList<JobKey>();
            jobKeys.addAll(scheduler.getJobKeys(gm));
            System.out.println("现有任务数：" + scheduler.getJobKeys(gm).size());
            scheduler.deleteJobs(jobKeys);
            System.out.println("剩余任务数：" + scheduler.getJobKeys(gm).size());

            List<String> gnames = scheduler.getJobGroupNames();
            for (String gn : gnames) {
                gm = GroupMatcher.groupEquals(gn);
                System.out.println("任务组【" + gn + "】中任务数：" + scheduler.getJobKeys(gm).size());
            }
        } catch (SchedulerException e) {
            logger.error("failed to delete tasks,", e);
        }
    }

    public void startResTask(Res res) {
        if (res.getPaused() != null && res.getPaused() == 1L) {
            return;
        }
        List<CollectTask> tasks = collectorService.getResCollectTasks(res);
        for (CollectTask t : tasks) {
            //add by wangyl
            if (t.getStatus().intValue() == 0) {
                continue;
            }
            addTask(res, t);
        }
    }

    public void deleteResTask(Long resId) {
        GroupMatcher<JobKey> gm = GroupMatcher.groupEquals("FIXED_" + resId);
        try {
            scheduler.getJobKeys(gm);
            List<JobKey> jobKeys = new ArrayList<JobKey>();
            jobKeys.addAll(scheduler.getJobKeys(gm));

            scheduler.deleteJobs(jobKeys);
        } catch (SchedulerException e) {
            logger.error("failed to delete task,resId:" + resId, e);
        }
    }

    public void restartResTask(Long resId) {
        deleteResTask(resId);
        Res res = resCache.get(resId);
        if (res != null) {
            startResTask(res);
        }
    }

    public void addTemporaryResTasks(Res res) {
        List<CollectTask> tasks = collectorService.getResCollectTasks(res);
        for (CollectTask t : tasks) {
            if (t.getStatus().intValue() == 0) {
                continue;
            }
            addTemporaryTask(res, t);
        }
    }

    public int getFixTaskCount() {
        GroupMatcher<JobKey> gm = GroupMatcher.groupStartsWith("FIXED_");
        try {
            scheduler.getJobKeys(gm);
            List<JobKey> jobKeys = new ArrayList<JobKey>();
            jobKeys.addAll(scheduler.getJobKeys(gm));
            return scheduler.getJobKeys(gm).size();
        } catch (SchedulerException e) {
            logger.error("failed to get task size,", e);
            return -1;
        }
    }

    /**
     * 
     * @return
     * @throws Exception
     */
    public synchronized List<JobExecutionContext> getCurrentlyExecutingJobs() throws Exception {
        return this.scheduler.getCurrentlyExecutingJobs();
    }

    private void addTask(Res res, CollectTask task) {
        String jobName = "FIXED_" + res.getId() + "_" + task.getId();
        String groupName = "FIXED_" + res.getId();

        JobDetail job = newJob(CollectJob.class).withIdentity(jobName, groupName).build();
        job.getJobDataMap().put(CollectJob.JOB_KEY_RESID, res.getId());
        job.getJobDataMap().put(CollectJob.JOB_KEY_TASKID, task.getId());
        job.getJobDataMap().put("IS_TEMPORARY", false);
        try {
            scheduler.addJob(job, true);
        } catch (SchedulerException e) {
            logger.error("failed to add task job:" + jobName, e);
        }
        List<CollectSchedule> schedules = collectorService.getCollectTaskSchedules(task.getId());
        if (schedules != null) {
            for (CollectSchedule s : schedules) {
                String triggerName = jobName + "_" + s.getId();
                Trigger trigger = makeTrggier(job.getKey(), triggerName, s.getScheduleType(), s.getScheduleParam());
                if (trigger != null) {
                    try {
                        scheduler.scheduleJob(trigger);
                    } catch (Exception e) {
                        logger.error("failed to add task trigger:" + triggerName, e);
                    }
                }
            }
        }
    }

    private Trigger makeTrggier(JobKey jobKey, String triggerName, Long type, String parameter) {
        Trigger trigger = null;
        if (type == PropertyConstants.PROPERTY_REFRESH_PERIOD) {
            int interval = Integer.parseInt(parameter);
            trigger = newTrigger().withSchedule(simpleSchedule().withIntervalInSeconds(interval).repeatForever()).forJob(jobKey).withIdentity(triggerName).startAt(getJobStartTime()).build();
            trigger.getJobDataMap().put(JOB_KEY_INTERVAL, interval);
        } else if (type == PropertyConstants.PROPERTY_REFRESH_TIMER) {
            try {
                trigger = newTrigger().withSchedule(cronSchedule(parameter)).forJob(jobKey).withIdentity(triggerName).build();
                trigger.getJobDataMap().put(JOB_KEY_INTERVAL, "0");
            } catch (Exception e) {
                logger.error("property refresh timing trggier expression error:" + triggerName, e);
                return null;
            }
        } else {
            return null;
        }
        return trigger;
    }

    /**
     * 此方法暂时无用  
     * 因为le、opmanager所供的获取最近指标的方法都是从数据库中取的最近一条值
     * @param res
     * @param task
     */
    private void addTemporaryTask(Res res, CollectTask task) {
        return;
        //        String jobName = "TEMP_" + res.getId() + "_" + task.getId();
        //        String groupName = "TEMPORARY";
        //        JobDetail job = newJob(CollectJob.class).withIdentity(jobName, groupName).build();
        //        job.getJobDataMap().put(JOB_KEY_INTERVAL, 10);
        //        job.getJobDataMap().put("IS_TEMPORARY", true);
        //        job.getJobDataMap().put(CollectJob.JOB_KEY_RESID, res.getId());
        //        job.getJobDataMap().put(CollectJob.JOB_KEY_TASKID, task.getId());
        //        try {
        //            scheduler.addJob(job, true);
        //            scheduler.triggerJob(job.getKey());
        //        } catch (SchedulerException e) {
        //            logger.error(e);
        //        }
    }

    private Date getJobStartTime() {
        Calendar cl = Calendar.getInstance();
        cl.setTimeInMillis(cl.getTimeInMillis() + (long) (Math.random() * 60 * 1000L));
        return cl.getTime();
    }
}
